package com.yonyougov.devops.cruxcisupport.k8s.service;

import com.yonyougov.devops.cruxcisupport.k8s.K8sRepository;
import com.yonyougov.devops.cruxcisupport.k8s.error.K8sConfIgNotFindException;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.ServiceBuilder;
import io.fabric8.kubernetes.api.model.ServicePort;
import io.fabric8.kubernetes.client.KubernetesClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Repository
public class ServiceRepositoryImpl implements ServiceRepository {
    private final K8sRepository k8sRepository;

    public ServiceRepositoryImpl(K8sRepository k8sRepository) {
        this.k8sRepository = k8sRepository;
    }

    @Override
    public Service createOrReplace(ServiceRequest serviceRequest) throws K8sConfIgNotFindException {
        KubernetesClient client = k8sRepository.createDefaultClient(serviceRequest.getNameSpace());
        Service result = null;
        //判断端口信息是否发生变化
        boolean flag = isPortInfoChanged(serviceRequest,client);
        if(flag){
            try{
                List<ServicePortInfo> servicePortInfos = serviceRequest.getServicePortInfos();
                List<ServicePort> servicePorts = servicePortInfos.stream().map(servicePortInfo -> {
                    ServicePort servicePort = new ServicePort();
                    BeanUtils.copyProperties(servicePortInfo, servicePort);
                    return servicePort;
                }).collect(Collectors.toList());
                //创建service
                Service service = new ServiceBuilder()
                        .withNewMetadata()
                        .withName(serviceRequest.getServiceName())
                        .endMetadata()
                        .withNewSpec()
                        .withSelector(serviceRequest.getSelectors())
//                    .addNewPort()
//                    .withName(serviceRequest.getServicePortInfo().getName())
//                    .withProtocol(serviceRequest.getServicePortInfo().getProtocol())
//                    .withPort(serviceRequest.getServicePortInfo().getPort())
//                    .withTargetPort(new IntOrString(serviceRequest.getServicePortInfo().getTargetPort()))
//                    .withNodePort(serviceRequest.getServicePortInfo().getNodePort())
//                    .endPort()
                        .withPorts(servicePorts)
                        .withType("NodePort")
                        .endSpec()
                        .build();
                delete(client,serviceRequest.getNameSpace(), serviceRequest.getServiceName());
                // 删除service的结果集，进行轮询
                result = client.services().inNamespace(serviceRequest.getNameSpace()).create(service);
            }finally {
                client.close();
            }
        }else{
            result = get(client, serviceRequest.getNameSpace(), serviceRequest.getServiceName());
        }
        return result;
    }

    /**
     * 判断service信息是否发生变化
     * @param serviceRequest 用户传入的端口信息
     * @param client 客户端
     * @return boolean
     */
    private boolean isPortInfoChanged(ServiceRequest serviceRequest, KubernetesClient client) {
        List<ServicePortInfo> servicePortInfos = serviceRequest.getServicePortInfos();
        Service service = get(client, serviceRequest.getNameSpace(), serviceRequest.getServiceName());
        boolean result = true;
        if(null ==service){
            log.info("在环境:{}下,根据serviceName: {},查询不到,需要创建service",serviceRequest.getNameSpace(),serviceRequest.getServiceName());
        }else{
            List<ServicePort> ports = service.getSpec().getPorts();
            boolean flag = true;
            for (ServicePort servicePort : ports) {
                Integer port = servicePort.getPort();
                Integer targetPort = servicePort.getTargetPort().getIntVal();
                Integer nodePort = servicePort.getNodePort();
                for (ServicePortInfo servicePortInfo : servicePortInfos) {
                    Integer port1 = servicePortInfo.getPort();
                    Integer targetPort1 = servicePortInfo.getTargetPort();
                    Integer nodePort1 = servicePortInfo.getNodePort();
                    if(port.equals(port1) && targetPort.equals(targetPort1) && nodePort.equals(nodePort1)){
                        flag = false;
                        break;
                    }
                }
            }
            if(!flag){
                log.info("在环境:{}下,serviceName: {}的端口信息没有发生变化,不需要创建service",serviceRequest.getNameSpace(),serviceRequest.getServiceName());
                result = false;
            }else{
                log.info("在环境:{}下,serviceName: {}的端口信息发生变化,需要创建service",serviceRequest.getNameSpace(),serviceRequest.getServiceName());
            }
        }
        return result;
    }

    @Override
    public Service get(String nameSpace, String serviceName) throws K8sConfIgNotFindException {
        KubernetesClient client = k8sRepository.createDefaultClient(nameSpace);
        return get(client,nameSpace,serviceName);
    }

    @Override
    public Service get(KubernetesClient client, String nameSpace, String serviceName) {
        return client.services().inNamespace(nameSpace).withName(serviceName).get();
    }

    @Override
    public Service getServiceNameByAppName(String nameSpace, String appName) throws K8sConfIgNotFindException {
        KubernetesClient client = k8sRepository.createDefaultClient(nameSpace);
        return getServiceNameByAppName(client,nameSpace,appName);
    }

    @Override
    public Service getServiceNameByAppName(KubernetesClient client, String nameSpace, String appName) {
        return client.services().inNamespace(nameSpace).withName(appName + "-svc").get();
    }

    @Override
    public boolean delete(String nameSpace, String serviceName) throws K8sConfIgNotFindException {
        KubernetesClient client = k8sRepository.createDefaultClient(nameSpace);
        return delete(client,nameSpace,serviceName);
    }

    @Override
    public boolean delete(KubernetesClient client, String nameSpace, String serviceName) {
        Service service = get(client, nameSpace, serviceName);
        if(null == service){
            log.debug("Service[]: {} don't exist",serviceName);
            return true;
        }else{
            client.services().inNamespace(nameSpace).withName(serviceName).delete();
            //轮询10s查看service是否被删除
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    log.error("catch exception when delete service: {}",e.getMessage());
                }
                Service service1 = get(client, nameSpace, serviceName);
                if(null == service1){
                    return true;
                }
            }
        }
        return  false;
    }

}
